#pragma once

#include <compl.h>

#include <dstruct/tstack.h>
#include <frame/coreid.h>
/* 实现thread local storage的数据结构 */
typedef struct threadlocal{
    struct{
        tsnode_t    node;
        cid_t       cached_cid;
        hword_t     tid;
        struct threadlocal *next;
    }ALIGN(HDEF_CACHE_LINE_BYTES);
    
    char tldata[];
}threadlocal_t;



SAI void *tls_getdataptr(threadlocal_t *p){
    return (void *)&p->tldata[0];
}
// 释放接口
SAI void tls_free(tstack_t *tlstk, threadlocal_t *p){
    // 挂到链表里
    tstack_push(tlstk, &p->node);
}

// 由用户申请和释放
SAI threadlocal_t *tls_create(void *ptr, word_t size, hword_t tid){
    threadlocal_t *p = (threadlocal_t *)ptr;
    __memset(p, 0, size);
    // 分配alloca
    p->tid = tid;
    p->cached_cid = get_coreid();

    // 注册
    return p;
}

SAI threadlocal_t *tls_tryalloc(tstack_t *tlstk){
    tsnode_t *nd = tstack_pop(tlstk);
    if (!nd) return NULL;
    threadlocal_t *l = tstack_entry(nd, threadlocal_t, node);
    return l;
}


DECL_INLINTF(void *, tls_init, ())
DECL_INLINTF(threadlocal_t **, tls_get_ptls, ())


// 定义宏给用户使用(放在atomic_threadinit里面调用)
#define DECL_PTHREADLOCAL(size)                                         \
static TLS_INITIAL threadlocal_t *my_tld;                               \
static unsigned int __max_threads = 0;                                  \
static tstack_t tlstk;                                                  \
static pthread_key_t tlkey;                                             \
static void tls_endcallback(void *value) { tls_free(&tlstk, my_tld); }  \
SAI void tls_init(){                           \
    threadlocal_t *p = tls_tryalloc(&tlstk);                                                            \
    if (!p) {                                                                                           \
        p = tls_create(aligned_malloc(HDEF_CACHE_LINE_BYTES, size), size, faa(&__max_threads, 1));      \
        if (p->tid == 0){                                                                               \
            pthread_key_create(&tlkey, tls_endcallback);                                                \
        }                                                                                               \
    }                                                                                                   \
    my_tld = p;                                                                                         \
    pthread_setspecific(tlkey, (void *)my_tld);                                                         \
}                                                                                                       \
SAI threadlocal_t *tls_get_ptls(){ return &my_tld; }